// PerformanceCollector.ts - 性能采集器
// @/utils/monitor/collectors/PerformanceCollector.ts

import { MonitorEventBus } from '../core/MonitorEventBus';
import { MonitorConfig, EventType, PerformanceEventData, ICollector } from '../MonitorTypes';

/**
 * 性能采集器
 * 采集页面导航时间、Web Vitals、资源加载时间、长任务等性能指标
 */
export class PerformanceCollector implements ICollector {
  public readonly name = 'PerformanceCollector';
  
  private eventBus: MonitorEventBus;
  private config: MonitorConfig;
  private observers: Map<string, PerformanceObserver>;
  private isStarted: boolean = false;
  private cleanup: Array<() => void> = [];

  constructor(eventBus: MonitorEventBus, config: MonitorConfig) {
    this.eventBus = eventBus;
    this.config = config;
    this.observers = new Map();
  }

  /**
   * 初始化采集器
   */
  public init(config: MonitorConfig): void {
    this.config = config;
  }

  /**
   * 启动性能采集
   */
  public start(): void {
    if (this.isStarted) {
      return;
    }

    this.collectNavigationTiming();
    this.collectWebVitals();
    this.collectResourceTiming();
    this.collectLongTasks();
    this.collectMiniProgramPerformance();
    
    this.isStarted = true;

    if (this.config.enableDebug) {
      console.log('[PerformanceCollector] Started performance tracking');
    }
  }

  /**
   * 停止性能采集
   */
  public stop(): void {
    if (!this.isStarted) {
      return;
    }

    this.observers.forEach(observer => observer.disconnect());
    this.observers.clear();
    
    // 清理所有事件监听器
    this.cleanup.forEach(fn => fn());
    this.cleanup = [];
    
    this.isStarted = false;

    if (this.config.enableDebug) {
      console.log('[PerformanceCollector] Stopped performance tracking');
    }
  }

  /**
   * 销毁采集器
   */
  public destroy(): void {
    this.stop();
  }

  /**
   * 收集导航时间
   */
  private collectNavigationTiming(): void {
    // #ifdef H5
    if (typeof window !== 'undefined' && 'performance' in window && 'getEntriesByType' in performance) {
      // 等待页面加载完成
      if (document.readyState === 'complete') {
        this.reportNavigationTiming();
      } else {
        const loadHandler = () => {
          setTimeout(() => this.reportNavigationTiming(), 0);
        };
        window.addEventListener('load', loadHandler);
        
        this.cleanup.push(() => {
          window.removeEventListener('load', loadHandler);
        });
      }
    }
    // #endif
  }

  /**
   * 上报导航时间
   */
  private reportNavigationTiming(): void {
    // #ifdef H5
    if (typeof performance === 'undefined') return;

    try {
      const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
      
      if (navigation) {
        const performanceData: PerformanceEventData = {
          type: 'navigation',
          timing: {
            // DNS 查询时间
            dns: Math.round(navigation.domainLookupEnd - navigation.domainLookupStart),
            // TCP 连接时间
            tcp: Math.round(navigation.connectEnd - navigation.connectStart),
            // SSL 连接时间
            ssl: navigation.secureConnectionStart > 0 
              ? Math.round(navigation.connectEnd - navigation.secureConnectionStart)
              : 0,
            // TTFB (Time to First Byte)
            ttfb: Math.round(navigation.responseStart - navigation.requestStart),
            // 数据传输时间
            download: Math.round(navigation.responseEnd - navigation.responseStart),
            // DOM 解析时间
            domParse: Math.round(navigation.domInteractive - navigation.responseEnd),
            // DOM 内容加载时间
            domContentLoaded: Math.round(navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart),
            // 页面完全加载时间
            loadComplete: Math.round(navigation.loadEventEnd - navigation.loadEventStart),
            // 总时间
            total: Math.round(navigation.loadEventEnd - navigation.fetchStart),
            // 重定向时间
            redirect: Math.round(navigation.redirectEnd - navigation.redirectStart)
          },
          redirectCount: navigation.redirectCount,
          navigationType: navigation.type
        };

        this.emitPerformance(performanceData);

        if (this.config.enableDebug) {
          console.log('[PerformanceCollector] Navigation timing collected:', performanceData);
        }
      }
    } catch (error) {
      if (this.config.enableDebug) {
        console.warn('[PerformanceCollector] Failed to collect navigation timing:', error);
      }
    }
    // #endif
  }

  /**
   * 收集Web Vitals
   */
  private collectWebVitals(): void {
    // #ifdef H5
    if (typeof window === 'undefined' || !('PerformanceObserver' in window)) {
      return;
    }

    // LCP (Largest Contentful Paint)
    this.observeLCP();
    
    // FID (First Input Delay)
    this.observeFID();
    
    // CLS (Cumulative Layout Shift)
    this.observeCLS();
    
    // FCP (First Contentful Paint)
    this.observeFCP();
    
    // TTFB (Time to First Byte)
    this.observeTTFB();
    // #endif
  }

  /**
   * 观察LCP
   */
  private observeLCP(): void {
    // #ifdef H5
    try {
      const observer = new PerformanceObserver((list) => {
        const entries = list.getEntries();
        const lastEntry = entries[entries.length - 1] as any;
        
        const performanceData: PerformanceEventData = {
          type: 'webvital',
          metric: 'lcp',
          value: Math.round(lastEntry.renderTime || lastEntry.loadTime),
          rating: this.getRating('lcp', lastEntry.renderTime || lastEntry.loadTime)
        };

        this.emitPerformance(performanceData);
      });
      
      observer.observe({ entryTypes: ['largest-contentful-paint'] });
      this.observers.set('lcp', observer);
    } catch (e) {
      if (this.config.enableDebug) {
        console.warn('[PerformanceCollector] LCP observation not supported:', e);
      }
    }
    // #endif
  }

  /**
   * 观察FID
   */
  private observeFID(): void {
    // #ifdef H5
    try {
      const observer = new PerformanceObserver((list) => {
        for (const entry of list.getEntries()) {
          const fid = Math.round((entry as any).processingStart - entry.startTime);
          
          const performanceData: PerformanceEventData = {
            type: 'webvital',
            metric: 'fid',
            value: fid,
            rating: this.getRating('fid', fid)
          };

          this.emitPerformance(performanceData);
        }
      });
      
      observer.observe({ entryTypes: ['first-input'] });
      this.observers.set('fid', observer);
    } catch (e) {
      if (this.config.enableDebug) {
        console.warn('[PerformanceCollector] FID observation not supported:', e);
      }
    }
    // #endif
  }

  /**
   * 观察CLS
   */
  private observeCLS(): void {
    // #ifdef H5
    try {
      let clsValue = 0;
      let sessionValue = 0;
      let sessionEntries: any[] = [];
      
      const observer = new PerformanceObserver((list) => {
        for (const entry of list.getEntries() as any[]) {
          // 只统计没有最近用户输入的布局偏移
          if (!entry.hadRecentInput) {
            const firstSessionEntry = sessionEntries[0];
            const lastSessionEntry = sessionEntries[sessionEntries.length - 1];
            
            // 如果距离上一次偏移超过1秒，或者距离第一次偏移超过5秒，开始新的会话
            if (sessionValue &&
                (entry.startTime - lastSessionEntry.startTime >= 1000 ||
                 entry.startTime - firstSessionEntry.startTime >= 5000)) {
              sessionValue = entry.value;
              sessionEntries = [entry];
            } else {
              sessionValue += entry.value;
              sessionEntries.push(entry);
            }
            
            // 更新最大会话值
            if (sessionValue > clsValue) {
              clsValue = sessionValue;
            }
          }
        }
        
        const performanceData: PerformanceEventData = {
          type: 'webvital',
          metric: 'cls',
          value: Math.round(clsValue * 1000) / 1000, // 保留3位小数
          rating: this.getRating('cls', clsValue)
        };

        this.emitPerformance(performanceData);
      });
      
      observer.observe({ entryTypes: ['layout-shift'] });
      this.observers.set('cls', observer);
    } catch (e) {
      if (this.config.enableDebug) {
        console.warn('[PerformanceCollector] CLS observation not supported:', e);
      }
    }
    // #endif
  }

  /**
   * 观察FCP
   */
  private observeFCP(): void {
    // #ifdef H5
    try {
      const observer = new PerformanceObserver((list) => {
        for (const entry of list.getEntries()) {
          if (entry.name === 'first-contentful-paint') {
            const performanceData: PerformanceEventData = {
              type: 'webvital',
              metric: 'fcp',
              value: Math.round(entry.startTime),
              rating: this.getRating('fcp', entry.startTime)
            };

            this.emitPerformance(performanceData);
          }
        }
      });
      
      observer.observe({ entryTypes: ['paint'] });
      this.observers.set('fcp', observer);
    } catch (e) {
      if (this.config.enableDebug) {
        console.warn('[PerformanceCollector] FCP observation not supported:', e);
      }
    }
    // #endif
  }

  /**
   * 观察TTFB
   */
  private observeTTFB(): void {
    // #ifdef H5
    if (typeof performance === 'undefined') return;

    try {
      const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
      
      if (navigation) {
        const ttfb = Math.round(navigation.responseStart - navigation.requestStart);
        
        const performanceData: PerformanceEventData = {
          type: 'webvital',
          metric: 'ttfb',
          value: ttfb,
          rating: this.getRating('ttfb', ttfb)
        };

        this.emitPerformance(performanceData);
      }
    } catch (error) {
      if (this.config.enableDebug) {
        console.warn('[PerformanceCollector] TTFB observation failed:', error);
      }
    }
    // #endif
  }

  /**
   * 收集资源时间
   */
  private collectResourceTiming(): void {
    // #ifdef H5
    if (typeof window === 'undefined' || !('PerformanceObserver' in window)) {
      return;
    }

    try {
      const observer = new PerformanceObserver((list) => {
        const resources = list.getEntries() as PerformanceResourceTiming[];
        
        resources.forEach(resource => {
          // 过滤掉监控上报请求
          if (resource.name.includes(this.config.endpoint)) {
            return;
          }
          
          const performanceData: PerformanceEventData = {
            type: 'resource',
            name: resource.name,
            resourceType: resource.initiatorType,
            duration: Math.round(resource.duration),
            size: (resource as any).transferSize || 0,
            protocol: resource.nextHopProtocol,
            timing: {
              dns: Math.round(resource.domainLookupEnd - resource.domainLookupStart),
              tcp: Math.round(resource.connectEnd - resource.connectStart),
              ssl: resource.secureConnectionStart > 0 
                ? Math.round(resource.connectEnd - resource.secureConnectionStart)
                : 0,
              ttfb: Math.round(resource.responseStart - resource.requestStart),
              download: Math.round(resource.responseEnd - resource.responseStart)
            }
          };
          
          // 只上报慢资源或大资源
          const isSlowResource = resource.duration > 1000;
          const isLargeResource = (resource as any).transferSize > 500 * 1024; // 500KB
          
          if (isSlowResource || isLargeResource) {
            this.emitPerformance(performanceData);
          }
        });
      });
      
      observer.observe({ entryTypes: ['resource'] });
      this.observers.set('resource', observer);
    } catch (e) {
      if (this.config.enableDebug) {
        console.warn('[PerformanceCollector] Resource timing observation not supported:', e);
      }
    }
    // #endif
  }

  /**
   * 收集长任务
   */
  private collectLongTasks(): void {
    // #ifdef H5
    if (typeof window === 'undefined' || !('PerformanceObserver' in window)) {
      return;
    }

    try {
      const observer = new PerformanceObserver((list) => {
        for (const entry of list.getEntries()) {
          const performanceData: PerformanceEventData = {
            type: 'longtask',
            duration: Math.round(entry.duration),
            startTime: Math.round(entry.startTime),
            attribution: (entry as any).attribution
          };

          this.emitPerformance(performanceData);
        }
      });
      
      observer.observe({ entryTypes: ['longtask'] });
      this.observers.set('longtask', observer);
    } catch (e) {
      if (this.config.enableDebug) {
        console.warn('[PerformanceCollector] Long task observation not supported:', e);
      }
    }
    // #endif
  }

  /**
   * 收集小程序性能
   */
  private collectMiniProgramPerformance(): void {
    // #ifdef MP
    if (typeof uni !== 'undefined') {
      try {
        // 获取小程序启动性能
        const performance = uni.getPerformance?.();
        if (performance) {
          const performanceData: PerformanceEventData = {
            type: 'miniprogram',
            appLaunch: performance.appLaunch,
            route: performance.route,
            render: performance.render
          };

          this.emitPerformance(performanceData);
        }

        // 监听路由性能
        const pages = getCurrentPages();
        if (pages.length > 0) {
          const currentPage = pages[pages.length - 1];
          const route = currentPage.route;
          
          const performanceData: PerformanceEventData = {
            type: 'route',
            route: route,
            timestamp: Date.now()
          };

          this.emitPerformance(performanceData);
        }
      } catch (error) {
        if (this.config.enableDebug) {
          console.warn('[PerformanceCollector] Miniprogram performance collection failed:', error);
        }
      }
    }
    // #endif
  }

  /**
   * 获取性能评级
   */
  private getRating(metric: string, value: number): 'good' | 'needs-improvement' | 'poor' | 'unknown' {
    const thresholds: Record<string, { good: number; poor: number }> = {
      lcp: { good: 2500, poor: 4000 },
      fid: { good: 100, poor: 300 },
      cls: { good: 0.1, poor: 0.25 },
      fcp: { good: 1800, poor: 3000 },
      ttfb: { good: 800, poor: 1800 }
    };
    
    const threshold = thresholds[metric];
    if (!threshold) return 'unknown';
    
    if (value <= threshold.good) return 'good';
    if (value <= threshold.poor) return 'needs-improvement';
    return 'poor';
  }

  /**
   * 发送性能事件
   */
  private emitPerformance(performanceData: PerformanceEventData): void {
    this.eventBus.emit(EventType.PERFORMANCE, {
      type: EventType.PERFORMANCE,
      data: performanceData,
      timestamp: Date.now()
    });

    if (this.config.enableDebug) {
      console.log('[PerformanceCollector] Performance data captured:', performanceData);
    }
  }

  /**
   * 获取采集器状态信息
   */
  public getStatus(): { isStarted: boolean; observersCount: number; name: string } {
    return {
      name: this.name,
      isStarted: this.isStarted,
      observersCount: this.observers.size
    };
  }
} 